package com.sbtr.impl;


import com.sbtr.business.calibration.service.ICalibrationFileService;
import com.sbtr.business.calibration.service.ICalibrationService;
import com.sbtr.business.calibration.service.ICalibrationVoiceService;
import com.sbtr.open.calibration.dto.CalibrationDto;
import com.sbtr.open.calibration.dto.CalibrationFileDto;
import com.sbtr.open.calibration.dto.CalibrationVoiceDto;
import com.sbtr.util.ZipUtil;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.MultimediaInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

/**
 * 标注声音处理service
 * 
 * @author zengjw5
 *
 */
@Service
public class CalibrationVoiceCommon {

	private static final Logger logger = LoggerFactory.getLogger(CalibrationVoiceCommon.class);

	@Value("${oss.config.uploadPath}")
	private String uploadPath;


	@Autowired
	private ICalibrationFileService calibrationFileService;

	@Autowired
	private ICalibrationVoiceService calibrationVoiceService;

	@Autowired
	private ICalibrationService calibrationService;

	/**
	 * 解压并保存相关音频文件
	 * @param calibrationDto
	 * @param calibrationFileDto
	 * @param finisher
	 * @return
	 * @throws Exception
	 */
	public boolean unzipAndSaveVoice(CalibrationDto calibrationDto, CalibrationFileDto calibrationFileDto, String finisher)throws Exception {
//		try {
			List<CalibrationVoiceDto> calibrationVoiceDtos = new ArrayList<>();
			// 文件上传完成：1、解压压缩包，2、将每个音频重新保存3、记录音频时长信息
			String bucketDir = calibrationFileDto.getBucketDir();//压缩包所在目录
			String filename2 = calibrationFileDto.getFileName2();//原压缩包文件名
			File zip = new File(bucketDir + File.separator + filename2);//压缩包路径
			String unZipTmp = bucketDir + File.separator + filename2+"_unzip";// 压缩包解压路径
			ZipUtil.unZip(zip, unZipTmp);//解压完成...

			//对解压目标文件夹里面的音频进行处理
			File unZipTmpFile = new File(unZipTmp);
			File[] listFiles = unZipTmpFile.listFiles();
			if (listFiles == null || listFiles.length == 0){
				throw new Exception("压缩包为空");
			}else if (listFiles.length == 1 && listFiles[0].isDirectory()) {//解压出来后，如果里面只有一个文件夹
				// 解压出来后目标文件夹里面是一个文件夹(选择一个文件夹进行压缩时, 音频在所选文件夹里)
				File[] listFiles2 = listFiles[0].listFiles();
				if (listFiles2 == null || listFiles2.length == 0){
					throw new Exception("压缩包为空");
				}else if (listFiles2.length != 1 && listFiles2[0].isDirectory()){
					throw new Exception("压缩包里存在多个文件夹，请把所有音频放在一个文件夹里");
				}
				for (File file : listFiles2) {
					// 是.wav音频文件才处理
					if (file.isFile() && CalibrationVoiceCommon.isVoice(file.getName())) {
						try(InputStream fIn = new FileInputStream(file);){
							CalibrationVoiceDto dto = saveVoiceNew(calibrationDto, calibrationFileDto, fIn, file.getName(), listFiles[0].getAbsolutePath());
							if (dto != null) {
								calibrationVoiceDtos.add(dto);
							}
						}
					}
					//file.delete(); // 处理完成删除文件
				}
				//listFiles[0].delete();
			} else if (listFiles.length != 1 && listFiles[0].isDirectory()){
				throw new Exception("压缩包里存在多个文件夹，请把所有音频放在一个文件夹里");
			} else {
				// 解压出来后多个文件夹目标文件夹里是音频文件(选择所有音频进行压缩时)
				for (File file : listFiles) {
					// 是音频文件才处理
					if (file.isFile() && CalibrationVoiceCommon.isVoice(file.getName())) {
						InputStream fIn = new FileInputStream(file);
						CalibrationVoiceDto dto = saveVoiceNew(calibrationDto, calibrationFileDto, fIn, file.getName(),unZipTmpFile.getAbsolutePath());
						if (dto != null) {
							calibrationVoiceDtos.add(dto);
						}
						fIn.close();
					}
					//file.delete(); // 原音频文件不删
				}
			}

			// 解压文件夹不删
			//unZipTmpFile.delete();
			zip.delete();//解压完，删除zip包（有待商榷）

			//设置每个人的条数
//			String newfinisher = finisher;
			if(StringUtils.isEmpty(finisher)){
				finisher = calibrationDto.getFinisher();
			}
			String finishers[]= finisher.split(",");
			int userlength=finishers.length;
			for(int i=0;i<calibrationVoiceDtos.size();i++){
				int j = i % userlength;
				calibrationVoiceDtos.get(i).setFinisher(finishers[j]);
			}

			//保存分割后的素材
			boolean tag = false;
			if (!calibrationVoiceDtos.isEmpty()) {
				tag = calibrationVoiceService.batchSave(calibrationVoiceDtos);
			}

			if (tag) {
				// 保存或更新发布任务和各个接收任务的数据
				tag = calibrationService.updateCalibrationAndCalibrationDetails(calibrationDto,finisher);
			}
			return tag;

//		} catch (IllegalArgumentException e) {
//			logger.error("上传音频异常", e);
//			String message = e.getMessage();
//			if ("音频名称太长".equals(message)) {
//				throw e;
//			}
//		} catch (IOException e) {
//			logger.error("上传zip文件异常", e);
//		}
//		return false;
	}

	//	保存zip文件包
	public CalibrationFileDto saveZip(MultipartFile file, CalibrationDto calibrationDto
	) {

		String fileName = file.getOriginalFilename();
		String otherName = UUID.randomUUID().toString().replaceAll("-", "")
				+ fileName.substring(fileName.lastIndexOf("."));

		String fileType = calibrationDto.getTaskType();
		String creater = calibrationDto.getCreater();

		String bucketDir = uploadPath + File.separator + "calibration" + File.separator + fileType + File.separator + creater;

		OutputStream os = null;
		InputStream inputStream = null;
		try {
			inputStream = file.getInputStream();
			// 2、保存到临时文件
			// 1K的数据缓冲
			byte[] bs = new byte[1024];
			// 读取到的数据长度
			int len;
			// 输出的文件流保存到本地文件
			File tempFile = new File(bucketDir);
			boolean results = tempFile.mkdirs();
			if (!tempFile.exists()) {
				tempFile.mkdirs();
			}
			os = new FileOutputStream(tempFile.getPath() + File.separator + otherName);
			// 开始读取
			while ((len = inputStream.read(bs)) != -1) {
				os.write(bs, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 完毕，关闭所有链接
			try {
				os.close();
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		CalibrationFileDto calibrationFiles=new CalibrationFileDto();
		if(calibrationDto.getId()!=null) {
			CalibrationFileDto calibrationFile = new CalibrationFileDto();
			calibrationFile.setBucketDir(bucketDir);
			calibrationFile.setCalibrationId(calibrationDto.getId());
			calibrationFile.setFileName(fileName);
			calibrationFile.setFileName2(otherName);
			calibrationFile.setFileSize(file.getSize());

			calibrationFiles=calibrationFileService.save(calibrationFile);

		}
		else {
			return null;
		}


		return calibrationFiles;
	}

	/**
	 * 根据文件名判断此文件是否为音频文件
	 *
	 * @param fileName
	 * @return
	 */
	public static boolean isVoice(String fileName) {
		if (StringUtils.isNotEmpty(fileName)) {
			Set<String> imageSuffix = new HashSet<>(Arrays.asList(".wav"));
			for (String suffix : imageSuffix) {
				if (fileName.endsWith(suffix)) {
					return true;
				}
			}
		}
		return false;
	}


	/**
	 * 1.利用解压后的文件输入流，生成缩略图，
	 * 2.填充并返回CalibrationImgDto(内含缩略图存放路径)
	 * @param calibrationDto       标注任务信息对象
	 * @param calibrationFileDto   zip包文件对象
	 * @param fileIn               原图片文件输入流
	 * @param originalFileName     原图片名
	 * @param unZipPath            原图的解压路径
	 * @return  CalibrationImgDto
	 */
	public CalibrationVoiceDto saveVoiceNew(CalibrationDto calibrationDto, CalibrationFileDto calibrationFileDto, InputStream fileIn, String originalFileName,String unZipPath) {
		Assert.isTrue(originalFileName.length() < 200, "图片名称太长");
		//1.保存图片原图
		if(StringUtils.isNotEmpty(originalFileName)){
			//解压文件夹/原文件夹/thumbnail/缩略图1.jpg
			String thumbnailPictureDir = unZipPath + File.separator + "thumbnail" + File.separator + originalFileName;
			if(uploadPath.contains("\\\\")){//双反斜杠  换  单反斜杠
				uploadPath = uploadPath.replace("\\\\","\\");
			}
			String thumbnailRelativePath = StringUtils.substringAfterLast(thumbnailPictureDir,uploadPath);
			String relativePath = thumbnailRelativePath.replace("thumbnail"+File.separator,"");


			Long duration = getVoiceInfo(unZipPath + File.separator+originalFileName);

			//生成CalibrationImgDto对象返回
			return generateCalibrationVoiceDto(calibrationDto.getCreater(), calibrationDto.getId(), calibrationFileDto.getId(),
					originalFileName, unZipPath + File.separator+originalFileName, duration, relativePath);

		}else{
			logger.error("保存文件异常，MultipartFile获取文件名为空");
		}
		return null;
	}

	//保存音频
	public CalibrationVoiceDto saveVoice(CalibrationDto calibrationDto, CalibrationFileDto calibrationFileDto, InputStream fileIn, String originalFileName) {
		Assert.isTrue(originalFileName.length() < 200, "文件名称太长");
		CalibrationVoiceDto dto = new CalibrationVoiceDto();

		String newFileName = UUID.randomUUID().toString().replaceAll("-", "")+getSuffix(originalFileName);

		if(StringUtils.isNotEmpty(originalFileName)){
			String pictureDir = calibrationFileDto.getBucketDir() + File.separator + calibrationFileDto.getId().toString()+ File.separator + newFileName;
			File sourceFile = new File(pictureDir);
			File sourceParent = sourceFile.getParentFile();
			if(!sourceParent.exists()){
				sourceParent.mkdirs();
			}
			try(FileOutputStream fos = new FileOutputStream(sourceFile);){

				//保存文件
				byte[] buff = new byte[1024];
				int len = -1;
				while((len = fileIn.read(buff)) > 0){
					fos.write(buff, 0, len);
				}
				fos.flush();
				fos.close();

				Long duration = getVoiceInfo(pictureDir);

				return generateCalibrationVoiceDto(calibrationDto.getCreater(), calibrationDto.getId(), calibrationFileDto.getId(),
						originalFileName, pictureDir, duration,null);
			}catch(IOException e){
				logger.error("处理文件上传异常", e);
			}
		}else{
			logger.error("保存文件异常，MultipartFile获取文件名为空");
		}
		return null;
	}

	/**
	 * 获取文件名后缀
	 * @param fileName
	 * @return
	 */
	private String getSuffix(String fileName){
		String suffix = "";
		if(!StringUtils.isEmpty(fileName) && fileName.indexOf('.') > 0){
			suffix = fileName.substring(fileName.indexOf('.'));
		}
		return suffix;
	}

	private CalibrationVoiceDto generateCalibrationVoiceDto(String creater, Long calibrationId, Long calibrationFileId, String pictureName, String pictureDir, Long duration, String relativePath) {
		CalibrationVoiceDto dto = new CalibrationVoiceDto();
		dto.setCreater(creater);
		dto.setCalibrationId(calibrationId);
		dto.setCalibrationFileId(calibrationFileId);
		dto.setCompleted("0");
		dto.setVoiceName(pictureName);
		dto.setVoiceDir(pictureDir);
		dto.setDuration(duration);
		dto.setRelativePath(relativePath);
		return dto;
	}

	public Long getVoiceInfo(String fileDir) {
		File file = new File(fileDir);
		if(file.exists()){
			try {
				long duration;
				Encoder encoder = new Encoder();
				MultimediaInfo m = encoder.getInfo(file);
				long ls = m.getDuration();
				if(ls == 0){
					logger.warn("音频的时长为0");
					duration = 0;
				}else{
					duration = ls / 1000;
					logger.warn("此音频时长为:" + duration + "秒！");
				}
				return duration;
			} catch (Exception e) {
				logger.error("获取音频时长失败, 音频dir "+fileDir, e);
			}
		}else{
			logger.error("音频不存在, 音频dir "+fileDir);
		}
		return null;
	}

	public InputStream readFile(String fileDir) {
		try {
			return new FileInputStream(new File(fileDir));
		} catch (FileNotFoundException e) {
			logger.error("读取文件【"+fileDir+"】异常", e);
		}
		return null;
	}

	public String createResultFile(List<CalibrationVoiceDto> calibrationVoiceDtoList, String bucketdir){
		//生成对应文件夹和音频
//		String bucketdir = uploadPath +"/"+"NewCalibration/" + File.separator +  UUID.randomUUID().toString().replaceAll("-", "");
		for (CalibrationVoiceDto calibrationVoiceDto: calibrationVoiceDtoList){
			String originalVoiceDir = calibrationVoiceDto.getVoiceDir();
			if(StringUtils.isNotEmpty(originalVoiceDir)){
				File originalFile = new File(originalVoiceDir);

				String newVoiceDir = bucketdir + File.separator + calibrationVoiceDto.getClassifyName() + File.separator + originalFile.getName();
				File newFile = new File(newVoiceDir);
				File sourceParent = newFile.getParentFile();
				if(!sourceParent.exists()){
					sourceParent.mkdirs();
				}
				try{
					InputStream	fin = new FileInputStream(originalFile);
					FileOutputStream fos = new FileOutputStream(newFile);

					//保存文件
					byte[] buff = new byte[1024];
					int len = -1;
					while((len = fin.read(buff)) > 0){
						fos.write(buff, 0, len);
					}
					fos.flush();
					fos.close();
					fin.close();
				}catch(IOException e){
					logger.error("创建文件异常", e);
				}
			}else{
				logger.error("保存文件异常，MultipartFile获取文件名为空");
			}
		}
		if(calibrationVoiceDtoList.size() == 0){
			File bucketDirFile = new File(bucketdir);
			if(!bucketDirFile.exists()){
				bucketDirFile.mkdirs();
			}
		}

		//压缩
		ZipUtil.zipFileWithTier(bucketdir, bucketdir+".zip");
		return bucketdir+".zip";
	}
}
